iT邦幫忙

0

Javascript 進階 5-11 總結:函式的常見陷阱題

  • 分享至 

  • xImage
  •  

這篇文章要來總結一些常見的陷阱

1

// This 的觀念
var myName = '全域';
var person = {
    myName: '小明',
    getName: function () {
        return this.myName;
    }
};
var getName = person.getName;
console.log(getName());
// 印出來的值為何?

這段程式的重點就是函式調用的地方

那我們來看看執行的結果

https://ithelp.ithome.com.tw/upload/images/20200226/20121770YxF5qTzjR2.png

這邊的關鍵點可以看到 console.log(getName()); 這邊是用簡易呼叫的方式,所以自然他的 this 的綁定 會是 全域。

2

// bind 的其餘參數
var myName = '全域';
var obj = {
    myName: '奇怪的函式',
    fn: function (a, b, c) {
        return this.myName + ',' + a + ',' + b +',' + c;
    }
};

var fnA = obj.fn;
var fnB = fnA.bind(null, 0);
console.log(fnB(1, 2));

// console.log 會印出哪個答案
// 全域, 0, 1, 2
// 奇怪的函式, 0, 1, 2
// null, 0, 1, 2
// 奇怪的函式, 1, 2, undefined

主要的解題重點就是在於,如果在非嚴格模式(sloppy mode)下,利用bind/ call/ apply的this的指向帶入 null 或是 undefined 的話,會自動將 this 指向全域的 window 物件。

所以當然答案是全域,而且利用 bind 的方式多傳入了一個參數0,之後又再執行的時候才又傳入了參數1, 2,所以順序當然是0, 1, 2,最後的結果就是 全域, 0, 1, 2

https://ithelp.ithome.com.tw/upload/images/20200226/20121770vOqcApgoI5.png

3

延續上個問題喔,如果我們想要結果印出來是 null, 0, 1, 2的話該怎麼半?

很簡單喔~就只要讓函式執行的時候進入嚴格模式(strict mode)就好。

// bind 的其餘參數
var myName = '全域';
var obj = {
    myName: '奇怪的函式',
    fn: function (a, b, c) {
        'use strict'; // <<<<<<<< 加入這段
        return this + ',' + a + ',' + b +',' + c; // <<<<<< 移除myName的變數
    }
};

var fnA = obj.fn;
var fnB = fnA.bind(null, 0);
console.log(fnB(1, 2));

4

// This 的觀念
var value = 'global';
var foo = {
    value: 'local',
    bar: function () {
        return this.value;
    }
};

// 直接執行
console.log(foo.bar());
// 賦值
console.log((foo.bar = foo.bar)());
// or
console.log((false || foo.bar)());

可以看到第一個 console.log(foo.bar()); 是在 foo 的物件下執行 bar 這個 function,所以 this 的指向很明顯是 local。

再來第二個,console.log((foo.bar = foo.bar)()); 利用 = 賦值運算子會回傳右邊的內容做為回傳值,在這邊就是回傳了右邊的 foo.bar,那麼這樣取出來的其實就是函式本身,之後又在外層有一個括號的運算子,後面又直接執行,這樣的狀況視為簡易呼叫的概念。

https://ithelp.ithome.com.tw/upload/images/20200226/201217703mwWRCJgqY.png

所以答案會是 global。

最後一個 or 的運算子,當左邊的運算元是 falsy 的結果的時候就會回傳右邊的運算元內容,所以狀況跟第二個一樣,也是回傳右邊的 foo.bar 的 function,那麼答案自然也是 global。

https://ithelp.ithome.com.tw/upload/images/20200226/201217706wV9l5xbu6.png

5

// Callback Function
var arr = ['1', '2', '3'].map(parseInt);
console.log(arr);

// [1, 2, 3]
// [undefined, undefined, undefined]
// [1, NaN, NaN]
// [1, undefined, undefined]

我們先來看看結果是
https://ithelp.ithome.com.tw/upload/images/20200226/20121770BJNCuQxeEL.png

好,我們先分別來看看 map() 以及 parseInt() 這兩個方法是甚麼

map()

https://ithelp.ithome.com.tw/upload/images/20200226/201217704wjeOol84q.png

map 就是會依序把陣列的每個項目運算過後,並回傳一個新的 arr 陣列

var arr = ['1', '2', '3'].map(function (item) {
   console.log(item);
    return 'a' + item;
});

https://ithelp.ithome.com.tw/upload/images/20200226/201217706D651uN3OA.png

parseInt()

https://ithelp.ithome.com.tw/upload/images/20200226/20121770MpSvMrPc14.png

https://ithelp.ithome.com.tw/upload/images/20200226/20121770f2AbRflNvH.png

也就是說,parseInt() 第一個參數是要轉換成數字的字串,第二個參數是要用多少的進位數,如果都不設定,預設是 10 進位。

var arr = ['1', '2', '3'].map(function (item) {
    console.log(item);
    return parseInt(item, 10);
});

https://ithelp.ithome.com.tw/upload/images/20200226/20121770m77nuoVTdz.png

講解完兩個方法之後我們來解析為什麼答案會是 [1, NaN, NaN]

主要的原因是 map 所帶入的 callback function 中,所帶入的參數不只有 item 一個

https://ithelp.ithome.com.tw/upload/images/20200226/201217701LgeCYsPna.png

主要有
item => 當前的對象
index => 當前的對象在該陣列中的索引值
array => 這個陣列的本身

那麼我們來看看原本的程式碼是

// Callback Function
var arr = ['1', '2', '3'].map(parseInt);
console.log(arr);

但它其實相當於:

var arr = ['1', '2', '3'].map(function (item, index) {
    return parseInt(item, index);
});

所以當 1 進去的時候,parseInt('1', 0); => 答案是 1
當 2 進去的時候,parseInt('2', 1); => 答案是 NaN
當 3 進去的時候,parseInt('3', 2); => 答案是 NaN

PS: 進為模式的觀念其實是這樣

https://ithelp.ithome.com.tw/upload/images/20200226/20121770vnT7HHKrGH.png

當你是用 0 作為進位指定基數,它就會直接回傳你原本的值。

當你是用 1 作為進位指定基數,它就會直接回傳你NaN。

當你是用 2 作為進位指定基數,它就會依照你的0跟1字串來進行演算。

其他進位模式各位也可以試著練習看看喔,今天就先這樣~希望對大家有幫助~汪汪


圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言